﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using JTLeigh.Commerce.Spencer.Features.ProductImages.Common.Entities;
using JTLeigh.Commerce.Spencer.Features.ProductImages.Data.Providers;
using JTLeigh.Commerce.Spencer.Core.Testing;
using JTLeigh.Commerce.Spencer.Core.Testing.Mocks.Data;

namespace JTLeigh.Commerce.Spencer.Features.ProductImages.Data.UnitTests.Providers
{

	/// <summary>
	/// Unit tests for the <see cref="ProductImageProvider"/> class.
	/// </summary>
	[TestClass]
	public class ProductImageProviderFixture
	{

		#region Inner Classes and Types

		private static class Constants
		{

			public static class ProductImage
			{

				public static class ImageId
				{
					public static readonly Guid Image1 = new Guid("0FA3B974-14A6-4d00-919D-58630523B983");
					public static readonly Guid Image2 = new Guid("CB5991E4-0665-4711-9D87-02934F4126FD");
				}

			}

			public static class ProductImageView
			{

				public static class ViewId
				{
					public static readonly Guid Front = new Guid("32583D4F-673D-4a7b-BDEA-4FA444264B92");
					public static readonly Guid Left = new Guid("8A282AC2-195A-4962-87EE-318960F731A2");
				}

			}

			public static class ProductImageSize
			{

				public static class SizeId
				{
					public static readonly Guid Thumbnail = new Guid("176CE418-6309-4d9f-928C-8CFE344D40A8");
					public static readonly Guid Small = new Guid("E60FF2A3-3EC7-44d6-913F-4FB6BD9FDDE1");
					public static readonly Guid Medium = new Guid("2B22C915-C251-4345-99CC-20B511C19297");
					public static readonly Guid Large = new Guid("F675D9B1-AE08-4c63-A84B-F8BE0B370E9B");
				}

			}

		}

		private static class StoredProcedure
		{

			public static class GetProductImages
			{

				public static class Table
				{

					public static readonly DataTable ProductImage;
					public static readonly DataTable ProductImageLocalization;
					public static readonly DataTable ProductImageVariant;

					[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Reviewed.")]
					static Table()
					{
						ProductImage = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductImage.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImage.ImageId, typeof(Guid)));
						ProductImage.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImage.ViewId, typeof(Guid)));
						ProductImage.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImage.DefaultAlternativeText, typeof(string)));
						ProductImage.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImage.DefaultUsagePermissionText, typeof(string)));

						ProductImageLocalization = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductImageLocalization.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImage.ImageId, typeof(Guid)));
						ProductImageLocalization.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImageLocalization.CultureId, typeof(int)));
						ProductImageLocalization.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImageLocalization.AlternativeText, typeof(string)));
						ProductImageLocalization.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImageLocalization.UsagePermissionText, typeof(string)));

						ProductImageVariant = new DataTable
						{
							Locale = CultureInfo.InvariantCulture
						};
						ProductImageVariant.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImage.ImageId, typeof(Guid)));
						ProductImageVariant.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImageVariant.SizeId, typeof(Guid)));
						ProductImageVariant.Columns.Add(new DataColumn(ProductImageProvider.StoredProcedure.GetProductImages.ColumnName.ProductImageVariant.Path, typeof(string)));
					}

				}

			}

		}

		#endregion // Inner Classes and Types

		#region Methods

		#region GetProductImages

		/// <summary>
		/// Ensures <see cref="ProductImageProvider.GetProductImages"/> gets product images from 
		/// the database.
		/// </summary>
		[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Reviewed.")]
		[TestMethod]
		public void TestGetProductImages()
		{
			DataTable productImageResults;
			DataTable productImageLocalizationResults;
			DataTable productImageVariantResults;
			DataTable[] results;
			DataTableReader reader;
			MockDatabaseCommandExecuteReaderReturns command;
			MockDatabaseConnection connection;
			MockDatabaseConnectionFactory connectionFactory;
			ProductImageProvider provider;
			Dictionary<Guid, ProductImage> images;
			ProductImage image;
			ProductImageLocalization localization;
			ProductImageVariant variant;

			productImageResults = StoredProcedure.GetProductImages.Table.ProductImage.Clone();
			productImageResults.Rows.Add(Constants.ProductImage.ImageId.Image1, Constants.ProductImageView.ViewId.Front, "Image 1 Default Alternative Text", "Image 1 Default Usage Permission Text");
			productImageResults.Rows.Add(Constants.ProductImage.ImageId.Image2, Constants.ProductImageView.ViewId.Left, "Image 2 Default Alternative Text", "Image 2 Default Usage Permission Text");

			productImageLocalizationResults = StoredProcedure.GetProductImages.Table.ProductImageLocalization.Clone();
			productImageLocalizationResults.Rows.Add(Constants.ProductImage.ImageId.Image1, TestConstants.CultureId.EnglishCanada, "Image 1 English Alternative Text", "Image 1 English Usage Permission Text");
			productImageLocalizationResults.Rows.Add(Constants.ProductImage.ImageId.Image1, TestConstants.CultureId.FrenchCanada, "Image 1 French Alternative Text", "Image 1 French Usage Permission Text");
			productImageLocalizationResults.Rows.Add(Constants.ProductImage.ImageId.Image2, TestConstants.CultureId.EnglishCanada, "Image 2 English Alternative Text", "Image 2 English Usage Permission Text");
			productImageLocalizationResults.Rows.Add(Constants.ProductImage.ImageId.Image2, TestConstants.CultureId.FrenchCanada, "Image 2 French Alternative Text", "Image 2 French Usage Permission Text");

			productImageVariantResults = StoredProcedure.GetProductImages.Table.ProductImageVariant.Clone();
			productImageVariantResults.Rows.Add(Constants.ProductImage.ImageId.Image1, Constants.ProductImageSize.SizeId.Thumbnail, "/path/to/thumbnail/image1.gif");
			productImageVariantResults.Rows.Add(Constants.ProductImage.ImageId.Image1, Constants.ProductImageSize.SizeId.Small, "/path/to/small/image1.gif");
			productImageVariantResults.Rows.Add(Constants.ProductImage.ImageId.Image2, Constants.ProductImageSize.SizeId.Medium, "/path/to/medium/image2.gif");
			productImageVariantResults.Rows.Add(Constants.ProductImage.ImageId.Image2, Constants.ProductImageSize.SizeId.Large, "/path/to/large/image2.gif");

			results = new DataTable[]
			{
				productImageResults,
				productImageLocalizationResults,
				productImageVariantResults,
			};

			reader = new DataTableReader(results);

			command = new MockDatabaseCommandExecuteReaderReturns(ProductImageProvider.DatabaseSchema, ProductImageProvider.StoredProcedure.GetProductImages.CommandName, 3, reader);
			
			connection = new MockDatabaseConnection(command.Object);

			connectionFactory = new MockDatabaseConnectionFactory(TestConstants.TenantId.JTLeigh, ProductImageProvider.DatabaseKeyReadOperations, connection.Object);

			provider = new ProductImageProvider()
			{
				DatabaseConnectionFactory = connectionFactory.Object,
			};

			images = provider.GetProductImages(TestConstants.TenantId.JTLeigh, "BaseCatalog", "123");

			command.VerifyAll();
			connection.VerifyAll();

			Assert.IsNotNull(images);
			Assert.AreEqual(2, images.Count);

			Assert.IsTrue(images.TryGetValue(Constants.ProductImage.ImageId.Image1, out image));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image1, image.ImageId);
			Assert.AreEqual(Constants.ProductImageView.ViewId.Front, image.ViewId);
			Assert.AreEqual("Image 1 Default Alternative Text", image.DefaultAlternativeText);
			Assert.AreEqual("Image 1 Default Usage Permission Text", image.DefaultUsagePermissionText);
			Assert.AreEqual(2, image.Localizations.Count);
			Assert.IsTrue(image.Localizations.TryGetValue(TestConstants.CultureId.EnglishCanada, out localization));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image1, localization.ImageId);
			Assert.AreEqual(TestConstants.CultureId.EnglishCanada, localization.CultureId);
			Assert.AreEqual("Image 1 English Alternative Text", localization.AlternativeText);
			Assert.AreEqual("Image 1 English Usage Permission Text", localization.UsagePermissionText);
			Assert.IsTrue(image.Localizations.TryGetValue(TestConstants.CultureId.FrenchCanada, out localization));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image1, localization.ImageId);
			Assert.AreEqual(TestConstants.CultureId.FrenchCanada, localization.CultureId);
			Assert.AreEqual("Image 1 French Alternative Text", localization.AlternativeText);
			Assert.AreEqual("Image 1 French Usage Permission Text", localization.UsagePermissionText);
			Assert.AreEqual(2, image.Variants.Count);
			Assert.IsTrue(image.Variants.TryGetValue(Constants.ProductImageSize.SizeId.Thumbnail, out variant));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image1, variant.ImageId);
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Thumbnail, variant.SizeId);
			Assert.AreEqual("/path/to/thumbnail/image1.gif", variant.Path);
			Assert.IsTrue(image.Variants.TryGetValue(Constants.ProductImageSize.SizeId.Small, out variant));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image1, variant.ImageId);
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Small, variant.SizeId);
			Assert.AreEqual("/path/to/small/image1.gif", variant.Path);

			Assert.IsTrue(images.TryGetValue(Constants.ProductImage.ImageId.Image2, out image));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image2, image.ImageId);
			Assert.AreEqual(Constants.ProductImageView.ViewId.Left, image.ViewId);
			Assert.AreEqual("Image 2 Default Alternative Text", image.DefaultAlternativeText);
			Assert.AreEqual("Image 2 Default Usage Permission Text", image.DefaultUsagePermissionText);
			Assert.AreEqual(2, image.Localizations.Count);
			Assert.IsTrue(image.Localizations.TryGetValue(TestConstants.CultureId.EnglishCanada, out localization));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image2, localization.ImageId);
			Assert.AreEqual(TestConstants.CultureId.EnglishCanada, localization.CultureId);
			Assert.AreEqual("Image 2 English Alternative Text", localization.AlternativeText);
			Assert.AreEqual("Image 2 English Usage Permission Text", localization.UsagePermissionText);
			Assert.IsTrue(image.Localizations.TryGetValue(TestConstants.CultureId.FrenchCanada, out localization));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image2, localization.ImageId);
			Assert.AreEqual(TestConstants.CultureId.FrenchCanada, localization.CultureId);
			Assert.AreEqual("Image 2 French Alternative Text", localization.AlternativeText);
			Assert.AreEqual("Image 2 French Usage Permission Text", localization.UsagePermissionText);
			Assert.AreEqual(2, image.Variants.Count);
			Assert.IsTrue(image.Variants.TryGetValue(Constants.ProductImageSize.SizeId.Medium, out variant));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image2, variant.ImageId);
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Medium, variant.SizeId);
			Assert.AreEqual("/path/to/medium/image2.gif", variant.Path);
			Assert.IsTrue(image.Variants.TryGetValue(Constants.ProductImageSize.SizeId.Large, out variant));
			Assert.AreEqual(Constants.ProductImage.ImageId.Image2, variant.ImageId);
			Assert.AreEqual(Constants.ProductImageSize.SizeId.Large, variant.SizeId);
			Assert.AreEqual("/path/to/large/image2.gif", variant.Path);
		}

		#endregion // GetProductImages

		#endregion // Methods

	}

}
